package com.gopay.bis.icbc.bcdl.operation;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.crypto.dsig.TransformException;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.infosec.util.Base64;

import com.gopay.bis.common.util.TransUtil;
import com.gopay.bis.common.util.constants.Constants4BankSwitch;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.bank.IcbcConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.icbc.bcdl.pay.IcbcMessageData;
import com.gopay.common.domain.bank.icbc.bcdl.query.acctdetail.req.CMSReq;
import com.gopay.common.domain.bank.icbc.bcdl.query.acctdetail.req.EbReq;
import com.gopay.common.domain.bank.icbc.bcdl.query.acctdetail.req.InReq;
import com.gopay.common.domain.bank.icbc.bcdl.query.acctdetail.req.PubReq;
import com.gopay.common.exception.GopayException;
import com.thoughtworks.xstream.XStream;

public class QueryAcctDetailformer {
    
    /** Logger for logging information. */
    protected Logger log = LoggerFactory.getLogger(this.getClass());
    
    /** new Initiate capacity. */
    private static final int INIT_CAPACITY = 10;
    
    protected static final String SUC = "0";
    
    /** 交易代码. */
    protected String transCode = null;
    /** 集团CIS号. */
    protected String cis = null;
    /** 归属银行编号. */
    protected String bankCode = null;
    /** 证书ID. */
    protected String id = null;
    /** 商城账号. */
    protected String shopAcct = null;
    /** 版本号. */
    protected String version = null;
    /** 网银明细txt存储路径. */
    private String filePath = "/usr/local/ciecc/webapps/upload/ICBC/transDetail/txt/";
    
    public Object format(Object sendMsgData,String id) throws GopayException {
        return doFormat((IcbcMessageData) sendMsgData,id);
    }
    
    /**
     * Parse message.
     * 
     * @param receivedMsgData
     *            应答报文.
     * @return IcbcMessageData 工行数据结构体.
     * @throws TransformException
     *             报文格式错误.
     */
    public Object parse(Object receivedMsgData) throws GopayException {
        String msg = (String) receivedMsgData;
        try {
            msg = new String(msg.getBytes("UTF-8"), "GBK");
            String plainMsg = "";
            plainMsg = new String(Base64.decode(msg), "GBK");
            log.error("queryAcctDetail receive plainMsg: " + plainMsg);

            IcbcMessageData tranMsg = new IcbcMessageData();
            String returnCode = TransUtil.getMsgField(IcbcConstants.RETURN_CODE_BEGIN_TAG_NEW,
                    IcbcConstants.RETURN_CODE_END_TAG_NEW, plainMsg);

            if (SUC.equals(returnCode)) {
                return doParse(plainMsg);
            } else {
                String returnMsg = TransUtil.getMsgField(IcbcConstants.RETURN_MSG_BEGIN_TAG_NEW,
                        IcbcConstants.RETURN_MSG_END_TAG_NEW, plainMsg);
                tranMsg.setRetCode(StringUtils.isEmpty(returnCode) ? Constants4BankSwitch.DEFAULT_RETURN_CODE
                        : returnCode);
                tranMsg.setErrMsg(StringUtils.isEmpty(returnMsg) ? Constants4BankSwitch.DEFAULT_RETURN_MSG : returnMsg);
                tranMsg.setBank(BankConstants.BANK_LOGO_ICBC);
                return tranMsg;
            }
        } catch (Exception e) {
            log.error("queryAcctDetail parse error: ", e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6052);
        }
    }
    
    
    public Object doFormat(IcbcMessageData msg, String id) throws GopayException {
        try {
            msg.setTransCode(this.transCode);
            msg.setCis(this.cis);
            msg.setBankCode(this.bankCode);
            msg.setId(id);
            msg.setVersion(this.version);

            PubReq pub = new PubReq();
            pub.setTransCode(msg.getTransCode());
            pub.setCis(msg.getCis());
            pub.setBankCode(msg.getBankCode());
            pub.setId(msg.getId());
            pub.setTranDate(msg.getTranDate());
            pub.setTranTime(msg.getTranTime());
            pub.setfSeqno(msg.getfSeqno());

            InReq in = new InReq();
            in.setAccNo(this.shopAcct);
            in.setBeginDate(msg.getBeginDate());
            in.setEndDate(msg.getEndDate());
            in.setMinAmt(msg.getMinAmount());
            in.setMaxAmt(msg.getMaxAmount());
            in.setBankType("");
            in.setNextTag(msg.getNextTag());
            in.setCurrType(msg.getCurrType());
            in.setDueBillNo("");
            in.setAcctSeq("");
            in.setComplementFlag("");

            EbReq eb = new EbReq();
            eb.setPub(pub);
            eb.setIn(in);

            CMSReq cms = new CMSReq();
            cms.setEb(eb);

            XStream xstream = new XStream();
            xstream.autodetectAnnotations(true);
            xstream.processAnnotations(CMSReq.class);
            String cmsString = xstream.toXML(cms);
            StringBuffer xmlString = new StringBuffer("<?xml version=\"1.0\" encoding=\"GBK\" ?>\n");
            xmlString.append(cmsString);
            log.info("queryAcctDetail Message to be sent: \n" + xmlString.toString());
            return xmlString.toString().getBytes("UTF-8");
        } catch (Exception e) {
            log.error("queryAcctDetail doFormat error: ", e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6050);
        }
    }
    
    /**
     * 取得发送NetSafeClient的请求参数.
     * 
     * @param obj
     *            报文.
     * @param formatRes
     *            format res.
     * @return map.
     */
    public Map getIssueNCParaMap(Object obj, Object formatRes) throws GopayException {
        byte[] formatResByte = (byte[]) formatRes;
        try {
            formatResByte = new String(formatResByte).getBytes("GBK");

            IcbcMessageData msg = (IcbcMessageData) obj;
            String reqData = null;
            reqData = new String(formatResByte);

            // 组织提交工行所需form的field域及其值，报文体由IcbcConstants.REQ_DATA指定
            Map requestParaMap = new HashMap(INIT_CAPACITY);
            // 证书ID
            requestParaMap.put(IcbcConstants.USER_ID, msg.getId());
            // 请求时间
            requestParaMap.put(IcbcConstants.SEND_TIME, TransUtil.getSendTime());
            // 版本号（不同版本号对应的接口格式不同，请参考具体交易的接口文档)
            requestParaMap.put(IcbcConstants.VERSION, msg.getVersion());
            // 交易码
            requestParaMap.put(IcbcConstants.TRANS_CODE, msg.getTransCode());
            // 客户的归属单位
            requestParaMap.put(IcbcConstants.BANK_CODE, msg.getBankCode());
            // 客户的归属编码
            requestParaMap.put(IcbcConstants.GROUP_CIS, msg.getCis());
            // 客户的证书ID（无证书客户可空)
            requestParaMap.put(IcbcConstants.ID, msg.getId());
            // 客户的指令包序列号（由客户ERP系统产生，不可重复)
            requestParaMap.put(IcbcConstants.PACKAGE_ID, msg.getfSeqno());
            // 客户的证书公钥信息（进行BASE64编码；NC客户送空)
            requestParaMap.put(IcbcConstants.CERT, "");
            // 客户的xml请求数据,由相应的Formatter生成
            requestParaMap.put(IcbcConstants.REQ_DATA, reqData);
            return requestParaMap;
        } catch (UnsupportedEncodingException e1) {
            log.error("queryAcctDetail getIssueNCParaMap error: ", e1);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6050);
        }
    }
    
    protected Object doParse(String msg) throws DocumentException {
        IcbcMessageData tranMsg = new IcbcMessageData();
        tranMsg.setBank(BankConstants.BANK_LOGO_ICBC);
        tranMsg.setRetCode(SUC);
        Document document = DocumentHelper.parseText(msg);
        Element out = (Element) document.selectSingleNode("//CMS/eb/out");
        tranMsg.setNextTag(out.elementText("NextTag"));

        List<IcbcMessageData> details = new ArrayList<IcbcMessageData>();
        List resRd = document.selectNodes("/CMS/eb/out/rd");
        Iterator rds = resRd.iterator();
        while (rds.hasNext()) {
            Element rd = (Element) rds.next();
            IcbcMessageData detail = new IcbcMessageData();
            detail.setPayAccNo(out.elementText("AccNo"));
            detail.setRecAccNo(rd.elementText("RecipAccNo"));
            detail.setRecAccNameCN(rd.elementText("RecipName"));
            detail.setTransTime(rd.elementText("Time"));
            detail.setDcblType(Integer.parseInt(rd.elementText("Drcrf")));
            BigDecimal amount = new BigDecimal("0");
            if (1 == detail.getDcblType()) {
                amount = new BigDecimal(rd.elementText("DebitAmount"));
            } else if (2 == detail.getDcblType()) {
                amount = new BigDecimal(rd.elementText("CreditAmount"));
            }
            detail.setPayAmt(amount.movePointLeft(2).toString());
            detail.setSummary(rd.elementText("Summary"));
            detail.setUseCN(rd.elementText("UseCN"));
            detail.setPostScript(rd.elementText("PostScript"));
            details.add(detail);
        }
        tranMsg.setQryAcctDetail(details);
        return tranMsg;
    }
    
    public void saveFiles(IcbcMessageData message, String plainMsg) throws GopayException {
        try {
//            log.error("queryAcctDetail saveFiles plainMsg: " + plainMsg);
            
            File file = new File(filePath + "ICBC_BCDL_DETAILS_" + message.getTransTime() + ".txt");
            if (!file.exists()) {
                file.createNewFile();
            }

            FileWriter fw = new FileWriter(file, true);
            fw.write(plainMsg);
            fw.close();
        } catch (IOException e) {
            log.error("queryAcctDetail saveFiles error: ", e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6050);
        }
    }

    public String getTransCode() {
        return transCode;
    }

    public void setTransCode(String transCode) {
        this.transCode = transCode;
    }

    public String getCis() {
        return cis;
    }

    public void setCis(String cis) {
        this.cis = cis;
    }

    public String getBankCode() {
        return bankCode;
    }

    public void setBankCode(String bankCode) {
        this.bankCode = bankCode;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getShopAcct() {
        return shopAcct;
    }

    public void setShopAcct(String shopAcct) {
        this.shopAcct = shopAcct;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }
    
}
